home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / OS / FWGraphx / Sources / SLRender.cpp < prev    next >
Encoding:
Text File  |  1996-04-25  |  46.8 KB  |  1,827 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLRender.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWOS.hpp"
  11.  
  12. #ifndef SLRENDER_H
  13. #include "SLRender.h"
  14. #endif
  15.  
  16. #ifndef SLGC_H
  17. #include "SLGC.h"
  18. #endif
  19.  
  20. #ifndef FWRECT_H
  21. #include "FWRect.h"
  22. #endif
  23.  
  24. #ifndef FWPOINT_H
  25. #include "FWPoint.h"
  26. #endif
  27.  
  28. #ifndef PRGDEV_H
  29. #include "PRGDev.h"
  30. #endif
  31.  
  32. #ifndef PRMDASH_H
  33. #include "PRMDash.h"
  34. #endif
  35.  
  36. #ifndef SLREGION_H
  37. #include "SLRegion.h"
  38. #endif
  39.  
  40. #ifndef FWODGEOM_H
  41. #include "FWODGeom.h"
  42. #endif
  43.  
  44. #ifndef SLGRGLOB_H
  45. #include "SLGrGlob.h"
  46. #endif
  47.  
  48. #ifndef PRTXTBUF_H
  49. #include "PRTxtBuf.h"
  50. #endif
  51.  
  52. #ifndef SLPALETE_H
  53. #include "SLPalete.h"
  54. #endif
  55.  
  56. #ifndef PRICON_H
  57. #include "PRIcon.h"
  58. #endif
  59.  
  60. #ifndef PRGRUTIL_H
  61. #include "PRGrUtil.h"
  62. #endif
  63.  
  64. #ifndef PRPOLY_H
  65. #include "PRPoly.h"
  66. #endif
  67.  
  68. #ifndef FWGRUTIL_H
  69. #include "FWGrUtil.h"
  70. #endif
  71.  
  72. #ifndef PRPICTUR_H
  73. #include "PRPictur.h"
  74. #endif
  75.  
  76. #ifndef PRBITMAP_H
  77. #include "PRBitmap.h"
  78. #endif
  79.  
  80. #ifndef   SLMEMMGR_H
  81. #include "SLMemMgr.h"
  82. #endif
  83.  
  84. // ----- Platform Includes -----
  85.  
  86. #if defined(FW_BUILD_MAC) && !defined(__LOWMEM__)
  87. #include <LowMem.h>
  88. #endif
  89.  
  90. #if defined(FW_BUILD_MAC) && !defined(__ICONS__)
  91. #include <Icons.h>
  92. #endif
  93.  
  94. #ifdef FW_BUILD_MAC
  95. #pragma segment FWGraphx_Render
  96. #endif
  97.  
  98. //========================================================================================
  99. // Local helpers
  100. //========================================================================================
  101.  
  102. // All static method can fail
  103. static FW_PlatformCoordinate    PrivTextBox(Environment* ev,
  104.                                     FW_CPrivGraphicsDevice* device,
  105.                                     FW_CPrivTextBuffer *textBuffer, 
  106.                                     const FW_CPlatformRect& box,
  107.                                     FW_TextBoxOptions options,
  108.                                     FW_Boolean draw,
  109.                                     FW_HFont font);
  110.  
  111. static void                        PrivRenderTextBuffer(Environment* ev,
  112.                                     FW_SGraphicContext& gc,
  113.                                     FW_CPrivTextBuffer* textBuffer,
  114.                                     const FW_SPoint& position,
  115.                                     FW_TextAlignment textAlignment,
  116.                                     FW_ERenderVerbs renderVerb,
  117.                                     FW_HInk ink,
  118.                                     FW_HFont font);
  119.                                     
  120. static FW_Fixed                    PrivRenderTextBoxBuffer(Environment* ev,
  121.                                     FW_SGraphicContext& gc,
  122.                                     FW_CPrivTextBuffer* textBuffer, 
  123.                                     const FW_SRect& box,
  124.                                     FW_TextBoxOptions options,
  125.                                     FW_ERenderVerbs renderVerb,
  126.                                     FW_HInk ink,
  127.                                     FW_HFont font);
  128.  
  129. static void                        PrivTextBoxSizeBuffer(Environment* ev,
  130.                                     FW_SGraphicContext& gc,
  131.                                     FW_CPrivTextBuffer *textBuffer, 
  132.                                     FW_HFont font,
  133.                                     FW_TextBoxOptions options,
  134.                                     FW_SRect& textBox);
  135.                         
  136. static void                        PrivTextExtentBuffer(Environment* ev,
  137.                                     FW_SGraphicContext& gc,
  138.                                     FW_CPrivTextBuffer* textBuffer,
  139.                                     FW_HFont font, 
  140.                                     FW_SPoint& textExtent);
  141.  
  142. #ifdef FW_BUILD_MAC
  143.  
  144. static    FW_Boolean                MacSelectInkAndStyle(
  145.                                     FW_CPrivGraphicsDevice* device,
  146.                                     FW_EPrivShapeCategories shapeCategory,
  147.                                     FW_ERenderVerbs renderVerb,
  148.                                     FW_HInk ink,
  149.                                     FW_HStyle style);
  150.  
  151. static FW_CPlatformPoint        MacCalcTextPosition(
  152.                                     FW_CPrivGraphicsDevice* device,
  153.                                     short byteCount, const char* text,
  154.                                     FW_TextAlignment textAlignment,
  155.                                     const FW_CPlatformPoint& position);
  156.  
  157. static void                        MacStrikeOut(
  158.                                     FW_CPrivGraphicsDevice* device,
  159.                                     short beforePosX,
  160.                                     short beforePosY);    
  161. #endif
  162.  
  163. #ifdef FW_BUILD_WIN
  164. static DWORD                    WinConvertRasterOp(FW_TransferModes transferMode);
  165. #endif
  166.  
  167. //========================================================================================
  168. // Local macros to make rendering code more straightforward
  169. //========================================================================================
  170.  
  171. #ifdef FW_BUILD_WIN
  172.  
  173. #define FW_CHECK_RENDER    \
  174.     FW_ASSERT(&gc == FW_PrivGC_GetCurrent(ev));
  175.     
  176. #endif
  177.  
  178. #ifdef FW_BUILD_MAC
  179.  
  180. #define FW_CHECK_RENDER    \
  181.     FW_ASSERT(&gc == FW_PrivGC_GetCurrent(ev)); \
  182.     FW_ASSERT(gc.fGraphicDevice->GetPlatformCanvas() == FW_QDGlobals.thePort);
  183.     
  184. #endif
  185.  
  186. #define FW_CHECK_RENDER_VERB \
  187.     if (renderVerb == FW_kNoRendering) \
  188.         return;
  189.  
  190. #define FW_RENDER_PROLOG \
  191.     FW_CHECK_RENDER \
  192.     FW_CPrivGraphicsDevice* device = gc.fGraphicDevice;
  193.  
  194. #define FW_CHECK_INK \
  195.     FW_ASSERT(ink != NULL);
  196.     
  197. #define FW_CHECK_STYLE \
  198.     FW_ASSERT(style != NULL);
  199.     
  200. #define FW_CHECK_FONT \
  201.     FW_ASSERT(font != NULL);
  202.  
  203. //========================================================================================
  204. // Rendering APIs
  205. //========================================================================================
  206.  
  207. //----------------------------------------------------------------------------------------
  208. //    FW_PrivRenderRect
  209. //----------------------------------------------------------------------------------------
  210.  
  211. void SL_API FW_PrivRenderRect(Environment* ev,
  212.                             FW_SGraphicContext&     gc,
  213.                             const FW_SRect&         rect,
  214.                             FW_ERenderVerbs         renderVerb,
  215.                             FW_HInk                 ink,
  216.                             FW_HStyle                 style)
  217. {
  218.     FW_RENDER_PROLOG
  219.     FW_CHECK_RENDER_VERB
  220.     FW_CHECK_INK
  221.     FW_CHECK_STYLE
  222.  
  223.     FW_SOM_TRY
  224.     {
  225.         FW_CPlatformRect plfmRect;
  226.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  227.         FW_FailOnEvError(ev);
  228.             
  229.     #ifdef FW_BUILD_WIN
  230.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, 
  231.                                                         FW_kGeometricShapeWithInvert, 
  232.                                                         renderVerb);
  233.     
  234.         HDC hDC = *device;
  235.         if (frameBrush)
  236.         {
  237.             int penSizeX = device->fPenSize.x;
  238.             int penSizeY = device->fPenSize.y;
  239.     
  240.             device->fGDIBrush.SelectObject(hDC);
  241.             ::PatBlt(hDC, plfmRect.left, plfmRect.top, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  242.             ::PatBlt(hDC, plfmRect.right - penSizeX, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  243.             ::PatBlt(hDC, plfmRect.left, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  244.             ::PatBlt(hDC, plfmRect.left, plfmRect.bottom - penSizeY, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  245.         }
  246.         else
  247.         {
  248.             if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite)
  249.             {
  250.                 ::InvertRect(hDC, &plfmRect);
  251.             }
  252.             else
  253.             {
  254.                 if (renderVerb == FW_kFill)
  255.                 {
  256.                     plfmRect.right++;
  257.                     plfmRect.bottom++;
  258.                 }
  259.                     
  260.                 ::Rectangle(hDC, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  261.             }
  262.         }
  263.     #endif
  264.     #ifdef FW_BUILD_MAC
  265.         FW_Boolean styleIsDash = MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  266.     
  267.         if (renderVerb == FW_kFrame)
  268.         {
  269.             if (styleIsDash)
  270.             {
  271.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  272.     
  273.                 ::MoveTo(plfmRect.left, plfmRect.top);
  274.                 draw.LineTo(plfmRect.right - 1, plfmRect.top);
  275.                 draw.LineTo(plfmRect.right - 1, plfmRect.bottom - 1);
  276.                 draw.LineTo(plfmRect.left, plfmRect.bottom - 1);
  277.                 draw.LineTo(plfmRect.left, plfmRect.top);
  278.             }
  279.             else
  280.             {
  281.                 ::FrameRect(&plfmRect);
  282.             }
  283.         }
  284.         else
  285.         {
  286.             switch (ink->GetTransferMode())
  287.             {
  288.                 case FW_kErase:
  289.                     ::EraseRect(&plfmRect);
  290.                     break;
  291.     
  292.                 case FW_kInvert:
  293.                     ::InvertRect(&plfmRect);
  294.                     break;
  295.                     
  296.                 default:
  297.                     ::PaintRect(&plfmRect);            
  298.             }
  299.         }
  300.     #endif
  301.     }
  302.     FW_SOM_CATCH
  303. }
  304.  
  305. //----------------------------------------------------------------------------------------
  306. //    FW_PrivRenderOval
  307. //----------------------------------------------------------------------------------------
  308.  
  309. void SL_API    FW_PrivRenderOval(Environment* ev,
  310.                             FW_SGraphicContext&     gc,
  311.                             const FW_SRect&         rect,
  312.                             FW_ERenderVerbs         renderVerb,
  313.                             FW_HInk                 ink,
  314.                             FW_HStyle                 style)
  315. {
  316.     FW_RENDER_PROLOG
  317.     FW_CHECK_RENDER_VERB
  318.     FW_CHECK_INK
  319.     FW_CHECK_STYLE
  320.  
  321.     FW_SOM_TRY
  322.     {
  323.         FW_CPlatformRect plfmRect;
  324.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  325.         FW_FailOnEvError(ev);
  326.             
  327.     #ifdef FW_BUILD_WIN
  328.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  329.     
  330.         if (frameBrush)
  331.         {
  332.             HRGN hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, plfmRect.right + 1, plfmRect.bottom + 1);
  333.             ::FrameRgn(*device, hrgn, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  334.             ::DeleteObject(hrgn);
  335.         }
  336.         else
  337.         {
  338.             if (renderVerb == FW_kFill)
  339.             {
  340.                 plfmRect.right++;
  341.                 plfmRect.bottom++;
  342.             }
  343.     
  344.             ::Ellipse(*device, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  345.         }
  346.     #endif
  347.     #ifdef FW_BUILD_MAC
  348.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  349.         
  350.         if (renderVerb == FW_kFrame)
  351.         {
  352.             ::FrameOval(&plfmRect);
  353.         }
  354.         else
  355.         {
  356.             switch (ink->GetTransferMode())
  357.             {
  358.                 case FW_kErase:
  359.                     ::EraseOval(&plfmRect);
  360.                     break;
  361.                     
  362.                 case FW_kInvert:
  363.                     ::InvertOval(&plfmRect);
  364.                     break;
  365.                     
  366.                 default:
  367.                     ::PaintOval(&plfmRect);            
  368.             }
  369.         }
  370.     #endif
  371.     }
  372.     FW_SOM_CATCH
  373. }
  374.                             
  375. //----------------------------------------------------------------------------------------
  376. //    FW_PrivRenderRoundRect
  377. //----------------------------------------------------------------------------------------
  378.  
  379. void SL_API    FW_PrivRenderRoundRect(Environment* ev,
  380.                                     FW_SGraphicContext&     gc,
  381.                                     const FW_SRect&     rect,
  382.                                     const FW_SPoint&     ovalSize,
  383.                                     FW_ERenderVerbs     renderVerb,
  384.                                     FW_HInk             ink,
  385.                                     FW_HStyle             style)
  386. {
  387.     FW_RENDER_PROLOG
  388.     FW_CHECK_RENDER_VERB
  389.     FW_CHECK_INK
  390.     FW_CHECK_STYLE
  391.  
  392.     FW_SOM_TRY
  393.     {
  394.         FW_CPlatformRect plfmRect;
  395.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  396.         FW_FailOnEvError(ev);
  397.             
  398.         FW_CPlatformPoint plfmOvalSize;
  399.         FW_PrivGC_LogicalToDeviceSize(ev, gc, ovalSize.x, ovalSize.y, plfmOvalSize);
  400.         FW_FailOnEvError(ev);
  401.     
  402. #ifdef FW_BUILD_WIN
  403.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  404.     
  405.         if (frameBrush)
  406.         {
  407.             HRGN hrgn = NULL;
  408.             // There is a bug in Windows. If the size of the round rect is smaller than 1,  we are dead.
  409.             if ((plfmRect.right - plfmRect.left <= 1) || (plfmRect.bottom - plfmRect.top <= 1))
  410.                 hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, 
  411.                                             plfmRect.right + 1, plfmRect.bottom + 1);
  412.             else
  413.                 hrgn = ::CreateRoundRectRgn(plfmRect.left, plfmRect.top, 
  414.                                             plfmRect.right + 1, plfmRect.bottom + 1, 
  415.                                             plfmOvalSize.x, plfmOvalSize.y);
  416.                                             
  417.             ::FrameRgn(*device, hrgn, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  418.             ::DeleteObject(hrgn);
  419.         }
  420.         else
  421.         {
  422.             if (renderVerb == FW_kFill)
  423.             {
  424.                 plfmRect.right++;
  425.                 plfmRect.bottom++;
  426.             }
  427.         
  428.             ::RoundRect(*device, 
  429.                         plfmRect.left, plfmRect.top, 
  430.                         plfmRect.right, plfmRect.bottom,
  431.                         plfmOvalSize.x, plfmOvalSize.y);
  432.         }
  433. #endif
  434. #ifdef FW_BUILD_MAC
  435.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  436.         
  437.         if (renderVerb == FW_kFrame)
  438.         {
  439.             ::FrameRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  440.         }
  441.         else
  442.         {
  443.             switch (ink->GetTransferMode())
  444.             {
  445.                 case FW_kErase:
  446.                     ::EraseRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  447.                     break;
  448.                 case FW_kInvert:
  449.                     ::InvertRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  450.                     break;
  451.                 default:
  452.                     ::PaintRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);            
  453.             }
  454.         }
  455. #endif
  456.     }
  457.     FW_SOM_CATCH
  458. }
  459.                             
  460. //----------------------------------------------------------------------------------------
  461. //    FW_PrivRenderRoundRect
  462. //----------------------------------------------------------------------------------------
  463.  
  464. void SL_API    FW_PrivRenderArc(Environment* ev,
  465.                             FW_SGraphicContext&     gc,
  466.                             const FW_SRect&         rect, 
  467.                             short                     startAngle, 
  468.                             short                     arcAngle,
  469.                             FW_ERenderVerbs         renderVerb,
  470.                             FW_HInk                 ink,
  471.                             FW_HStyle                 style)
  472. {    
  473.     FW_RENDER_PROLOG
  474.     FW_CHECK_RENDER_VERB
  475.     FW_CHECK_INK
  476.     FW_CHECK_STYLE
  477.     
  478.     FW_SOM_TRY
  479.     {
  480.         FW_CPlatformRect arcRect;
  481.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, arcRect);
  482.         FW_FailOnEvError(ev);
  483.  
  484. #ifdef FW_BUILD_WIN    
  485.         short angle1 = startAngle;
  486.         
  487.         // Normalize the start angle
  488.         angle1 = angle1 % 360;
  489.         if (angle1 < 0)
  490.             angle1 += 360;
  491.             
  492.         // Compute and normalize the end angle
  493.         short angle2 = angle1 + arcAngle;
  494.         if (arcAngle < 0)
  495.         {
  496.             short temp = angle1;
  497.             angle1 = angle2;
  498.             angle2 = temp;
  499.         }
  500.     
  501.         FW_CPlatformPoint endPoint, startPoint;
  502.         FW_PrivCalcArcPoints(arcRect, angle1, endPoint);        // on Windows, arc and pie are drawn counterclockwise
  503.         FW_PrivCalcArcPoints(arcRect, angle2, startPoint);
  504.     
  505.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  506.     
  507.         if (renderVerb == FW_kFrame)
  508.         {
  509.             if(frameBrush)
  510.             {
  511.                 FW_CRect r = arcRect;
  512.                 ODRgnHandle rgnHandle = ::FW_CreateArcRegion(r, startAngle, arcAngle);
  513.                 ::FrameRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  514.                 ::FW_DisposeRegion(rgnHandle);
  515.             }
  516.             else
  517.             {
  518.                 ::Arc(*device, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  519.                     startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  520.             }
  521.         }
  522.         else
  523.         {
  524.             arcRect.right++;
  525.             arcRect.bottom++;
  526.             ::Pie(*device, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  527.                     startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  528.         }
  529. #endif
  530. #ifdef FW_BUILD_MAC
  531.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  532.         
  533.         if (renderVerb == FW_kFrame)
  534.         {
  535.             ::FrameArc(&arcRect, startAngle, arcAngle);
  536.         }
  537.         else
  538.         {
  539.             switch (ink->GetTransferMode())
  540.             {
  541.                 case FW_kErase:
  542.                     ::EraseArc(&arcRect, startAngle, arcAngle);
  543.                     break;
  544.                 case FW_kInvert:
  545.                     ::InvertArc(&arcRect, startAngle, arcAngle);
  546.                     break;
  547.                 default:
  548.                     ::PaintArc(&arcRect, startAngle, arcAngle);            
  549.             }
  550.         }
  551. #endif
  552.     }
  553.     FW_SOM_CATCH
  554. }
  555.  
  556. //----------------------------------------------------------------------------------------
  557. //     FW_RenderLine
  558. //----------------------------------------------------------------------------------------
  559.  
  560. void SL_API    FW_PrivRenderLine(Environment* ev,
  561.                                 FW_SGraphicContext&     gc,
  562.                                 const FW_SPoint&     start, 
  563.                                 const FW_SPoint&     end,
  564.                                 FW_ERenderVerbs     renderVerb,
  565.                                 FW_HInk             ink,
  566.                                 FW_HStyle             style)
  567. {
  568.     FW_RENDER_PROLOG
  569.     FW_CHECK_RENDER_VERB
  570.     FW_CHECK_INK
  571.     FW_CHECK_STYLE
  572.     
  573.     FW_SOM_TRY
  574.     {
  575.         FW_CPlatformPoint plfmStart;
  576.         FW_PrivGC_LogicalToDevicePoint(ev, gc, start, plfmStart);
  577.         FW_FailOnEvError(ev);
  578.  
  579.     
  580.         FW_CPlatformPoint plfmEnd;
  581.         FW_PrivGC_LogicalToDevicePoint(ev, gc, end, plfmEnd);
  582.         FW_FailOnEvError(ev);
  583.  
  584. #ifdef FW_BUILD_WIN
  585.         HDC hDC = device->GetPlatformCanvas();
  586.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, FW_kFrame);
  587.         
  588.         if (frameBrush)
  589.         {
  590.             int penSizeX = device->fPenSize.x;
  591.             int penHalfX = penSizeX / 2;
  592.             int penSizeY = device->fPenSize.y;
  593.             int penHalfY = penSizeY / 2;
  594.             if (plfmStart.x == plfmEnd.x)
  595.             {
  596.                 device->fGDIBrush.SelectObject(hDC);
  597.                 ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, penSizeX, plfmEnd.y - plfmStart.y, PATCOPY);
  598.             }
  599.             else if (plfmStart.y == plfmEnd.y)
  600.             {
  601.                 device->fGDIBrush.SelectObject(hDC);
  602.                 ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, plfmEnd.x - plfmStart.x, penSizeY, PATCOPY);
  603.             }
  604.             else
  605.             {
  606.                 HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(plfmStart), FW_CPoint(plfmEnd), FW_CPoint(device->fPenSize));        
  607.                 ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  608.                 ::DeleteObject(hRgn);
  609.             }
  610.         }
  611.         else
  612.         {
  613.             ::MoveToEx(hDC, plfmStart.x, plfmStart.y, NULL);
  614.             ::LineTo(hDC, plfmEnd.x, plfmEnd.y);
  615.         }
  616. #endif
  617. #ifdef FW_BUILD_MAC
  618.         FW_Boolean styleIsDash = MacSelectInkAndStyle(device,
  619.                             FW_kLineShape,
  620.                             FW_kFrame,                        // We never use FW_kFill for lines
  621.                             ink,
  622.                             style);    
  623.     
  624.         short halfPenh = FW_QDGlobals.thePort->pnSize.h / 2;
  625.         short halfPenv = FW_QDGlobals.thePort->pnSize.v / 2;
  626.         
  627.         ::MoveTo(plfmStart.h - halfPenh, plfmStart.v - halfPenv);
  628.         
  629.         if (styleIsDash && halfPenh == 0 && halfPenv == 0)
  630.         {
  631.             FW_CPrivMacDashDraw draw(style->GetDashStyle());
  632.             draw.LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  633.         }
  634.         else
  635.         {
  636.             ::LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  637.         }
  638. #endif
  639.     }
  640.     FW_SOM_CATCH
  641. }
  642.  
  643. //----------------------------------------------------------------------------------------
  644. //    FW_PrivRenderRegion
  645. //----------------------------------------------------------------------------------------
  646.  
  647. void SL_API    FW_PrivRenderRegion(Environment* ev,
  648.                                 FW_SGraphicContext&     gc,
  649.                                 ODShape*                 odShape,
  650.                                 FW_ERenderVerbs         renderVerb,
  651.                                 FW_HInk                 ink,
  652.                                 FW_HStyle                 style)
  653. {
  654.     FW_RENDER_PROLOG
  655.     FW_CHECK_RENDER_VERB
  656.     FW_CHECK_INK
  657.     FW_CHECK_STYLE
  658.     
  659.     FW_SOM_TRY
  660.     {
  661.         ODShape* deviceShape = FW_PrivGC_LogicalToDeviceShape(ev, gc, odShape);
  662.         FW_FailOnEvError(ev);
  663.         
  664.         ODRgnHandle rgnHandle = ::FW_GetShapeRegion(ev, deviceShape);
  665.         FW_ASSERT(rgnHandle != NULL);
  666.  
  667. #ifdef FW_BUILD_WIN
  668.         FW_ERenderVerbs localVerb = renderVerb == FW_kFrame ? FW_kFill : renderVerb;
  669.         device->SelectInkAndStyle(ink, style, FW_kGeometricShapeWithInvert, localVerb);
  670.     
  671.         switch (renderVerb)
  672.         {
  673.             case FW_kFrame:
  674.                 ::FrameRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  675.                 break;
  676.     
  677.             case FW_kFill:
  678.                 if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite)
  679.                     ::InvertRgn(*device, rgnHandle);
  680.                 else
  681.                     ::FillRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device));
  682.                 break;
  683.         }
  684. #endif
  685. #ifdef FW_BUILD_MAC
  686.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);        
  687.         
  688.         if (renderVerb == FW_kFrame)
  689.         {
  690.             ::FrameRgn(rgnHandle);
  691.         }
  692.         else
  693.         {
  694.             switch (ink->GetTransferMode())
  695.             {
  696.                 case FW_kErase:
  697.                     ::EraseRgn(rgnHandle);
  698.                     break;
  699.                 case FW_kXOr:
  700.                     ::InvertRgn(rgnHandle);
  701.                     break;
  702.                 default:
  703.                     ::PaintRgn(rgnHandle);            
  704.             }
  705.         }
  706. #endif
  707.         deviceShape->Release(ev);
  708.     }
  709.     FW_SOM_CATCH
  710. }
  711.  
  712. //----------------------------------------------------------------------------------------
  713. //    FW_PrivRenderPolygon
  714. //----------------------------------------------------------------------------------------
  715.  
  716. void SL_API    FW_PrivRenderPolygon(Environment* ev,
  717.                                 FW_SGraphicContext&     gc,
  718.                                 FW_HPolygon             polygon,
  719.                                 FW_ERenderVerbs         renderVerb,
  720.                                 FW_Boolean                 autoCloseFrame,
  721.                                 FW_HInk                 ink,
  722.                                 FW_HStyle                 style)
  723. {
  724.     FW_RENDER_PROLOG
  725.     FW_CHECK_RENDER_VERB
  726.     FW_CHECK_INK
  727.     FW_CHECK_STYLE
  728.     
  729.     FW_SOM_TRY
  730.     {
  731.         long count = polygon->GetCount();
  732.         const FW_SPoint* points = polygon->GetPoints();
  733.  
  734. #ifdef FW_BUILD_WIN
  735.         // Convert points to platform points
  736.         unsigned long plfmCount = count;
  737.         FW_Boolean needClose = FALSE;
  738.         if(renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  739.         {
  740.             ++ plfmCount;
  741.             needClose = TRUE;
  742.         }
  743.         
  744.         FW_CPlatformPoint* plfmPoints = new FW_CPlatformPoint[plfmCount];
  745.         for(long i = 0; i < count; i ++)
  746.             FW_PrivGC_LogicalToDevicePoint(gc, points[i], plfmPoints[i]);
  747.     
  748.         if(needClose)
  749.             plfmPoints[plfmCount - 1] = plfmPoints[0];
  750.     
  751.         // Prepare the graphics device
  752.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  753.     
  754.         int penSizeX = device->fPenSize.x;
  755.         int penHalfX = penSizeX / 2;
  756.         int penSizeY = device->fPenSize.y;
  757.         int penHalfY = penSizeY / 2;
  758.         
  759.         HDC hDC = *device;
  760.     
  761.         // Render the polygon
  762.         switch (renderVerb)
  763.         {
  764.             case FW_kFrame:
  765.                 if(frameBrush)
  766.                 {
  767.                     // Doing it like this is way, way faster than creating a polygon
  768.                     // region for the whole thing and framing it
  769.                     FW_CPlatformPoint pt0, pt1;
  770.                     BOOL bBrushSelected = FALSE;
  771.     
  772.                     for(unsigned long p = 0; p < plfmCount - 1; p ++)
  773.                     {
  774.                         pt0 = plfmPoints[p];
  775.                         pt1 = plfmPoints[p + 1];
  776.                         
  777.                         if (pt0.x == pt1.x)
  778.                         {
  779.                             if (!bBrushSelected)
  780.                             {
  781.                                 device->fGDIBrush.SelectObject(hDC);
  782.                                 bBrushSelected = TRUE;
  783.                             }
  784.     
  785.                             ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, penSizeX, pt1.y - pt0.y, PATCOPY);
  786.                         }
  787.                         else if (pt0.y == pt1.y)
  788.                         {
  789.                             if (!bBrushSelected)
  790.                             {
  791.                                 device->fGDIBrush.SelectObject(hDC);
  792.                                 bBrushSelected = TRUE;
  793.                             }
  794.     
  795.                             ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, pt1.x - pt0.x, penSizeY, PATCOPY);
  796.                         }
  797.                         else
  798.                         {
  799.                             HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(pt0), FW_CPoint(pt1), FW_CPoint(device->fPenSize));
  800.                             ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  801.                             ::DeleteObject(hRgn);
  802.                         }
  803.                     }
  804.                 }
  805.                 else
  806.                 {
  807.                     ::Polyline(hDC, plfmPoints, plfmCount);
  808.                 }
  809.                 break;
  810.     
  811.             case FW_kFill:
  812.                 ::Polygon(hDC, plfmPoints, plfmCount);
  813.                 break;
  814.         }
  815.         
  816.         delete[] plfmPoints;
  817. #endif
  818. #ifdef FW_BUILD_MAC
  819.         // Create a polygon
  820.         GrafPtr savePort;
  821.         ::GetPort(&savePort);
  822.         ::SetPort(FW_gScratchPort);
  823.         PolyHandle polyHandle = ::OpenPoly();
  824.         
  825.         if(polyHandle == NULL)
  826.         {
  827.             ::SetPort(savePort);
  828.             FW_Failure(FW_xMemoryExhausted);
  829.         }
  830.     
  831.         FW_CPlatformPoint plfmPoint;
  832.         FW_PrivGC_LogicalToDevicePoint(ev, gc, points[0], plfmPoint);
  833.         FW_FailOnEvError(ev);
  834.         
  835.         ::MoveTo(plfmPoint.h, plfmPoint.v);
  836.     
  837.         for(long i = 1; i < count; i ++)
  838.         {
  839.             FW_PrivGC_LogicalToDevicePoint(ev, gc, points[i], plfmPoint);
  840.             FW_FailOnEvError(ev);
  841.             
  842.             ::LineTo(plfmPoint.h, plfmPoint.v);
  843.         }
  844.         
  845.         // Close the polygon if needed
  846.         if(renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  847.         {
  848.             FW_PrivGC_LogicalToDevicePoint(ev, gc, points[0], plfmPoint);
  849.             FW_FailOnEvError(ev);
  850.             
  851.             ::LineTo(plfmPoint.h, plfmPoint.v);
  852.         }
  853.     
  854.         ::ClosePoly();
  855.         ::SetPort(savePort);
  856.     
  857.         // Prepare the grafport
  858.         FW_Boolean styleIsDash = MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);        
  859.         
  860.         // Render the polygon
  861.         if (renderVerb == FW_kFrame)
  862.         {
  863.             if (styleIsDash)
  864.             {
  865.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  866.                 short nPolyCount = ((*polyHandle)->polySize - 10) / sizeof(Point);
  867.                 ::MoveTo((*polyHandle)->polyPoints[0].h, (*polyHandle)->polyPoints[0].v);
  868.                 for (short n = 1; n < nPolyCount; ++ n)
  869.                     draw.LineTo((*polyHandle)->polyPoints[n].h, (*polyHandle)->polyPoints[n].v);
  870.             }
  871.             else
  872.             {
  873.                 ::FramePoly(polyHandle);
  874.             }
  875.         }
  876.         else
  877.         {
  878.             switch (ink->GetTransferMode())
  879.             {
  880.                 case FW_kErase:
  881.                     ::ErasePoly(polyHandle);
  882.                     break;
  883.                 case FW_kXOr:
  884.                     ::InvertPoly(polyHandle);
  885.                     break;
  886.                 default:
  887.                     ::PaintPoly(polyHandle);            
  888.             }
  889.         }
  890.     
  891.         ::KillPoly(polyHandle);
  892. #endif
  893.     }
  894.     FW_SOM_CATCH
  895. }                                            
  896.  
  897. //----------------------------------------------------------------------------------------
  898. //    FW_PrivRenderTextString
  899. //----------------------------------------------------------------------------------------
  900.  
  901. void SL_API    FW_PrivRenderTextString(Environment* ev,
  902.                                     FW_SGraphicContext&    gc,
  903.                                     FW_HString            string,
  904.                                     const FW_SPoint&    position,
  905.                                     FW_TextAlignment    textAlignment,
  906.                                     FW_ERenderVerbs        renderVerb,
  907.                                     FW_HInk             ink,
  908.                                     FW_HFont             font)
  909. {
  910.     FW_SOM_TRY
  911.     {
  912.         FW_CPrivTextBuffer buffer(string);
  913.         PrivRenderTextBuffer(ev, gc, &buffer, position, textAlignment, renderVerb, ink, font);
  914.     }
  915.     FW_SOM_CATCH
  916. }
  917.                                 
  918. //----------------------------------------------------------------------------------------
  919. //    FW_PrivRenderTextReader
  920. //----------------------------------------------------------------------------------------
  921.  
  922. void SL_API    FW_PrivRenderTextReader(Environment* ev,
  923.                                     FW_SGraphicContext&    gc,
  924.                                     FW_HTextReader        reader,
  925.                                     const FW_SPoint&    position,
  926.                                     FW_TextAlignment    textAlignment,
  927.                                     FW_ERenderVerbs        renderVerb,
  928.                                     FW_HInk                ink,
  929.                                     FW_HFont            font)
  930. {
  931.     FW_SOM_TRY
  932.     {
  933.         FW_CPrivTextBuffer buffer(reader);
  934.         PrivRenderTextBuffer(ev, gc, &buffer, position, textAlignment, renderVerb, ink, font);
  935.     }
  936.     FW_SOM_CATCH
  937. }
  938.  
  939. //----------------------------------------------------------------------------------------
  940. //    PrivRenderTextBuffer
  941. //----------------------------------------------------------------------------------------
  942.  
  943. static void    PrivRenderTextBuffer(Environment* ev,
  944.                                 FW_SGraphicContext&    gc,
  945.                                 FW_CPrivTextBuffer*    textBuffer,
  946.                                 const FW_SPoint&    position,
  947.                                 FW_TextAlignment    textAlignment,
  948.                                 FW_ERenderVerbs        renderVerb,
  949.                                 FW_HInk                ink,
  950.                                 FW_HFont            font)
  951. {    
  952.     FW_RENDER_PROLOG
  953.     FW_CHECK_RENDER_VERB
  954.     FW_CHECK_FONT
  955.     FW_CHECK_INK
  956.  
  957.     FW_ASSERT(textBuffer != NULL);
  958.     if (textBuffer->IsDone())    // No text to draw
  959.         return;
  960.  
  961.     FW_CPlatformPoint plfmPos;
  962.     FW_PrivGC_LogicalToDevicePoint(ev, gc, position, plfmPos);
  963.     FW_FailOnEvError(ev);
  964.  
  965.     // ----- RenderText only cares about the first line -----    
  966.     const char* text;
  967.     FW_ByteCount count;
  968.     textBuffer->GetCurrentLine(text, count);
  969.  
  970. #ifdef FW_BUILD_WIN
  971.     device->SelectInkAndFont(ink, font);
  972.         
  973.     // ----- Set the text alignment - always use TA_UPDATECP (see below)
  974.     TEXTMETRIC tm;
  975.     UINT newAlign = TA_UPDATECP;
  976.     
  977.     switch (textAlignment & FW_kPrivTextAlignVertAlignMask)
  978.     {
  979.         case FW_kTextAlignTop:
  980.             newAlign |= TA_TOP;
  981.             break;
  982.             
  983.         case FW_kTextAlignBottom:
  984.             newAlign |= TA_BOTTOM;
  985.             break;
  986.             
  987.         case FW_kTextAlignVCenter:
  988.             ::GetTextMetrics(*device, &tm);
  989.             plfmPos.y -= (tm.tmHeight - tm.tmInternalLeading) / 2;
  990.             break;
  991.             
  992.         case FW_kTextAlignBaseLine:
  993.             newAlign |= TA_BASELINE;
  994.             break;
  995.     }
  996.  
  997.     switch (textAlignment & FW_kPrivTextAlignHorzAlignMask)
  998.     {
  999.         case FW_kTextAlignLeft:
  1000.             newAlign |= TA_LEFT;
  1001.             break;
  1002.             
  1003.         case FW_kTextAlignRight:
  1004.             newAlign |= TA_RIGHT;
  1005.             break;
  1006.             
  1007.         case FW_kTextAlignHCenter:
  1008.             newAlign |= TA_CENTER;
  1009.             break;
  1010.     }
  1011.     
  1012.     // It is necessary to use TA_UPDATECP because the next call may want to use
  1013.     //    FW_kTextAlignUseCurrentPos.  However, TA_UPDATECP also means "use CP", so
  1014.     //    if this is not what the user wants, we should move to the right pos first
  1015.  
  1016.     if((textAlignment & FW_kPrivTextAlignUsePosMask) == FW_kTextAlignUseSpecifiedPos)
  1017.         ::MoveToEx(*device, plfmPos.x, plfmPos.y, NULL);
  1018.  
  1019.     ::SetTextAlign(*device, newAlign);
  1020.     ::TextOut(*device,
  1021.             0, 0,        // we use TA_UPDATECP, remember?
  1022.             text,
  1023.             count);
  1024.             
  1025.     ::SetTextAlign(*device, TA_LEFT | TA_TOP | TA_NOUPDATECP);        // restore the flags
  1026. #endif
  1027. #ifdef FW_BUILD_MAC
  1028.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  1029.     device->SelectFont(font, TRUE);        // SetInGrafPort called by SelectFont
  1030.  
  1031.     // ----- The Mac only knows to draw text from the baseline, so we need to do some adjustment
  1032.     FW_CPlatformPoint plfmTextPos = MacCalcTextPosition(device, count, text, textAlignment, plfmPos);
  1033.     
  1034.     // ----- Draw the text
  1035.     ::MoveTo(plfmTextPos.h, plfmTextPos.v);
  1036.     ::DrawText(text, 0, count);
  1037.  
  1038.     // ----- StrikeOut if necessary
  1039.     if ((font->GetFontStyle() & FW_kStrikeOut) != 0)
  1040.         MacStrikeOut(device, plfmTextPos.h, plfmTextPos.v);
  1041. #endif
  1042. }
  1043.                                 
  1044. //----------------------------------------------------------------------------------------
  1045. //    FW_PrivRenderTextBoxBuffer
  1046. //----------------------------------------------------------------------------------------
  1047.  
  1048. FW_Fixed SL_API FW_PrivRenderTextBoxString(Environment* ev,
  1049.                                             FW_SGraphicContext&    gc,
  1050.                                             FW_HString            string, 
  1051.                                             const FW_SRect&        box,
  1052.                                             FW_TextBoxOptions    options,
  1053.                                             FW_ERenderVerbs        renderVerb,
  1054.                                             FW_HInk                ink,
  1055.                                             FW_HFont            font)
  1056. {
  1057.     FW_SOM_TRY
  1058.     {
  1059.         FW_CPrivTextBuffer buffer(string);
  1060.         return PrivRenderTextBoxBuffer(ev, gc, &buffer, box, options, renderVerb, ink, font);
  1061.     }
  1062.     FW_SOM_CATCH
  1063.     return FW_kFixed0;
  1064. }
  1065.  
  1066. //----------------------------------------------------------------------------------------
  1067. //    FW_PrivRenderTextBoxBuffer
  1068. //----------------------------------------------------------------------------------------
  1069.  
  1070. FW_Fixed SL_API FW_PrivRenderTextBoxReader(Environment* ev,
  1071.                                             FW_SGraphicContext&    gc,
  1072.                                             FW_HTextReader        reader, 
  1073.                                             const FW_SRect&        box,
  1074.                                             FW_TextBoxOptions    options,
  1075.                                             FW_ERenderVerbs        renderVerb,
  1076.                                             FW_HInk                ink,
  1077.                                             FW_HFont            font)
  1078. {
  1079.     FW_SOM_TRY
  1080.     {
  1081.         FW_CPrivTextBuffer buffer(reader);
  1082.         return PrivRenderTextBoxBuffer(ev, gc, &buffer, box, options, renderVerb, ink, font);
  1083.     }
  1084.     FW_SOM_CATCH
  1085.     return FW_kFixed0;
  1086. }
  1087.  
  1088. //----------------------------------------------------------------------------------------
  1089. //    PrivRenderTextBoxBuffer
  1090. //----------------------------------------------------------------------------------------
  1091.  
  1092. static FW_Fixed    PrivRenderTextBoxBuffer(Environment* ev,
  1093.                                         FW_SGraphicContext& gc,
  1094.                                         FW_CPrivTextBuffer* textBuffer, 
  1095.                                         const FW_SRect& box,
  1096.                                         FW_TextBoxOptions options,
  1097.                                         FW_ERenderVerbs renderVerb,
  1098.                                         FW_HInk ink,
  1099.                                         FW_HFont font)
  1100. {
  1101.     FW_RENDER_PROLOG
  1102.     FW_CHECK_FONT
  1103.     FW_CHECK_INK
  1104.     
  1105.     FW_ASSERT(textBuffer != NULL);
  1106.     if (renderVerb == FW_kNoRendering || textBuffer->IsDone())
  1107.         return box.top;
  1108.         
  1109.     FW_CPlatformRect plfmBox;
  1110.     FW_PrivGC_LogicalToDeviceRect(ev, gc, box, plfmBox);
  1111.     FW_FailOnEvError(ev);
  1112.  
  1113. #ifdef FW_BUILD_WIN
  1114.     device->SelectInkAndFont(ink, font);
  1115. #endif
  1116. #ifdef FW_BUILD_MAC
  1117.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  1118.     device->SelectFont(font, TRUE);
  1119. #endif
  1120.  
  1121.     FW_PlatformCoordinate bottom = PrivTextBox(ev, device, textBuffer, plfmBox, options, TRUE, font);
  1122.  
  1123.     if (bottom != plfmBox.bottom)
  1124.     {
  1125.         FW_CPlatformPoint pt(0, bottom);
  1126.         FW_CPoint cPt;
  1127.         FW_PrivGC_DeviceToLogicalPoint(ev, gc, pt, cPt);
  1128.         FW_FailOnEvError(ev);
  1129.         return cPt.y;
  1130.     }
  1131.     
  1132.     return box.bottom;
  1133. }
  1134.                                 
  1135. //----------------------------------------------------------------------------------------
  1136. //    FW_PrivTextBoxSizeString
  1137. //----------------------------------------------------------------------------------------
  1138.  
  1139. void SL_API FW_PrivTextBoxSizeString(Environment* ev,
  1140.                                     FW_SGraphicContext&    gc,
  1141.                                     FW_HString            string, 
  1142.                                     FW_HFont            font,
  1143.                                     FW_TextBoxOptions    options,
  1144.                                     FW_SRect&            textBox)
  1145. {
  1146.     FW_SOM_TRY
  1147.     {
  1148.         FW_CPrivTextBuffer buffer(string);
  1149.         PrivTextBoxSizeBuffer(ev, gc, &buffer, font, options, textBox);
  1150.     }
  1151.     FW_SOM_CATCH
  1152. }
  1153.  
  1154. //----------------------------------------------------------------------------------------
  1155. //    FW_PrivTextBoxSizeReader
  1156. //----------------------------------------------------------------------------------------
  1157.  
  1158. void SL_API FW_PrivTextBoxSizeReader(Environment* ev,
  1159.                                     FW_SGraphicContext&    gc,
  1160.                                     FW_HTextReader        reader, 
  1161.                                     FW_HFont            font,
  1162.                                     FW_TextBoxOptions    options,
  1163.                                     FW_SRect&            textBox)
  1164. {
  1165.     FW_SOM_TRY
  1166.     {
  1167.         FW_CPrivTextBuffer buffer(reader);
  1168.         PrivTextBoxSizeBuffer(ev, gc, &buffer, font, options, textBox);
  1169.     }
  1170.     FW_SOM_CATCH
  1171. }
  1172.  
  1173. //----------------------------------------------------------------------------------------
  1174. //    PrivTextBoxSizeBuffer
  1175. //----------------------------------------------------------------------------------------
  1176.  
  1177. static void PrivTextBoxSizeBuffer(Environment* ev,
  1178.                                     FW_SGraphicContext& gc,
  1179.                                     FW_CPrivTextBuffer *textBuffer, 
  1180.                                     FW_HFont font,
  1181.                                     FW_TextBoxOptions options,
  1182.                                     FW_SRect& textBox)
  1183. {
  1184.     FW_RENDER_PROLOG
  1185.     FW_CHECK_FONT
  1186.     
  1187.     FW_ASSERT((const void*)font != NULL);
  1188.     FW_ASSERT(textBuffer != NULL);
  1189.  
  1190.     FW_CPlatformRect plfmBox;
  1191.     FW_PrivGC_LogicalToDeviceRect(ev, gc, textBox, plfmBox);
  1192.     FW_FailOnEvError(ev);
  1193.  
  1194.     if (textBuffer->IsDone())
  1195.     {
  1196.         plfmBox.bottom = plfmBox.top;
  1197.     }
  1198.     else
  1199.     {
  1200.         device->SelectFont(font, TRUE);                    // TRUE: scale
  1201.         plfmBox.bottom = PrivTextBox(ev, device, textBuffer, plfmBox, options, FALSE, font);    // FALSE: don't draw
  1202.     }
  1203.  
  1204.     FW_CPoint textBoxSize;
  1205.     FW_PrivGC_DeviceToLogicalSize(ev, gc, plfmBox.right, plfmBox.bottom, textBoxSize);
  1206.     FW_FailOnEvError(ev);
  1207.     
  1208.     textBox.right    = textBox.left + textBoxSize.x;
  1209.     textBox.bottom    = textBox.top  + textBoxSize.y;
  1210. }
  1211.  
  1212. //----------------------------------------------------------------------------------------
  1213. //    FW_PrivCalcTextExtentString
  1214. //----------------------------------------------------------------------------------------
  1215.  
  1216. void SL_API FW_PrivCalcTextExtentString(Environment* ev,
  1217.                                         FW_SGraphicContext&        gc,
  1218.                                         FW_HString                 string,
  1219.                                         FW_HFont                 font,
  1220.                                         FW_SPoint&                 textExtent)
  1221. {
  1222.     FW_SOM_TRY
  1223.     {
  1224.         FW_CPrivTextBuffer buffer(string);
  1225.         PrivTextExtentBuffer(ev, gc, &buffer, font, textExtent);
  1226.     }
  1227.     FW_SOM_CATCH
  1228. }
  1229.  
  1230. //----------------------------------------------------------------------------------------
  1231. //    FW_PrivCalcTextExtentReader
  1232. //----------------------------------------------------------------------------------------
  1233.  
  1234. void SL_API FW_PrivCalcTextExtentReader(Environment* ev,
  1235.                                         FW_SGraphicContext&    gc,
  1236.                                         FW_HTextReader        reader,
  1237.                                         FW_HFont            font, 
  1238.                                         FW_SPoint&            textExtent)
  1239. {
  1240.     FW_SOM_TRY
  1241.     {
  1242.         FW_CPrivTextBuffer buffer(reader);
  1243.         PrivTextExtentBuffer(ev, gc, &buffer, font, textExtent);
  1244.     }
  1245.     FW_SOM_CATCH
  1246. }
  1247.  
  1248. //----------------------------------------------------------------------------------------
  1249. //    PrivTextExtentBuffer
  1250. //----------------------------------------------------------------------------------------
  1251.  
  1252. static void PrivTextExtentBuffer(Environment* ev,
  1253.                                 FW_SGraphicContext& gc,
  1254.                                 FW_CPrivTextBuffer* textBuffer,
  1255.                                 FW_HFont font, 
  1256.                                 FW_SPoint& textExtent)
  1257. {
  1258.     FW_RENDER_PROLOG
  1259.     FW_CHECK_FONT
  1260.  
  1261.     if (textBuffer->IsDone())
  1262.     {
  1263.         textExtent = FW_kZeroPoint;
  1264.         return;
  1265.     }
  1266.     
  1267.     device->SelectFont(font, TRUE);
  1268.     
  1269.     // ----- TextExtent only cares about the first line -----    
  1270.     FW_ByteCount count;
  1271.     const char* text;
  1272.     textBuffer->GetCurrentLine(text, count);
  1273.  
  1274. #ifdef FW_BUILD_WIN
  1275.     SIZE size;
  1276.     ::GetTextExtentPoint32(*device, text, count, &size);
  1277.     FW_CPlatformPoint plfmExtent(size.cx, size.cy);
  1278. #endif
  1279. #ifdef FW_BUILD_MAC
  1280.     FontInfo fi;
  1281.     ::GetFontInfo(&fi);
  1282.     
  1283.     FW_CPlatformPoint plfmExtent(
  1284.             ::TextWidth(text, 0, count),
  1285.             fi.ascent + fi.descent);
  1286. #endif
  1287.  
  1288.     FW_PrivGC_DeviceToLogicalSize(ev, gc, plfmExtent.X(), plfmExtent.Y(), textExtent);
  1289.     FW_FailOnEvError(ev);
  1290. }
  1291.  
  1292. //----------------------------------------------------------------------------------------
  1293. //    FW_PrivRenderPicture
  1294. //----------------------------------------------------------------------------------------
  1295.  
  1296. void SL_API    FW_PrivRenderPicture(Environment* ev,
  1297.                                 FW_SGraphicContext& gc,
  1298.                                 FW_HPicture picture,
  1299.                                 const FW_SRect& dstRect,
  1300.                                 FW_ERenderVerbs renderVerb)
  1301. {
  1302.     FW_RENDER_PROLOG
  1303.     FW_CHECK_RENDER_VERB
  1304.     
  1305.     FW_SOM_TRY
  1306.     {
  1307.         FW_ASSERT(picture != NULL);
  1308.         FW_PlatformPict pict = picture->GetPlatformPict();
  1309.         FW_CPlatformRect plfmRect;
  1310.         FW_PrivGC_LogicalToDeviceRect(ev, gc, dstRect, plfmRect);
  1311.         FW_FailOnEvError(ev);
  1312.     
  1313. #ifdef FW_BUILD_WIN
  1314.         ::PlayEnhMetaFile(*device, pict, &plfmRect);
  1315. #endif
  1316. #ifdef FW_BUILD_MAC
  1317.         ::DrawPicture(pict, &plfmRect);
  1318. #endif
  1319.     }
  1320.     FW_SOM_CATCH
  1321. }
  1322.  
  1323. //----------------------------------------------------------------------------------------
  1324. //    FW_PrivRenderBitmap
  1325. //----------------------------------------------------------------------------------------
  1326.  
  1327. void SL_API    FW_PrivRenderBitmap(Environment* ev,
  1328.                                 FW_SGraphicContext& gc,
  1329.                                 FW_HBitmap bitmap,
  1330.                                 const FW_SRect& srcRect,
  1331.                                 const FW_SRect& dstRect,
  1332.                                 FW_ERenderVerbs renderVerb,
  1333.                                 FW_HInk ink)
  1334. {
  1335.     FW_RENDER_PROLOG
  1336.     FW_CHECK_RENDER_VERB
  1337.  
  1338.     FW_ASSERT(bitmap != NULL);
  1339.     
  1340.     FW_SOM_TRY
  1341.     {
  1342.         // Convert source and destination rectangles
  1343.         FW_CPlatformRect plfmDstRect;
  1344.         FW_PrivGC_LogicalToDeviceRect(ev, gc, dstRect, plfmDstRect);
  1345.         FW_FailOnEvError(ev);
  1346.         
  1347.         FW_CPlatformRect plfmSrcRect = srcRect;
  1348.     
  1349. #ifdef FW_BUILD_WIN
  1350.         ::SetTextColor(*device, ink->GetForeColor());
  1351.         ::SetBkColor(*device, ink->GetBackColor());
  1352.         
  1353.         HDC hDC = *device;
  1354.     
  1355.         HBITMAP plfmBitmap = bitmap->GetPlatformBitmap();
  1356.     
  1357.         HDC memoryDC = ::CreateCompatibleDC(*device);
  1358.         HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, plfmBitmap);
  1359.     
  1360.         HPALETTE hPal = bitmap->GetPalette();
  1361.         HPALETTE hPalOld = NULL;
  1362.         if (hPal != NULL)
  1363.         {
  1364.             hPalOld = ::SelectPalette(hDC, hPal, FALSE);
  1365.             ::RealizePalette(hDC);
  1366.         }
  1367.     
  1368.         ::StretchBlt(hDC,
  1369.                     plfmDstRect.left,
  1370.                     plfmDstRect.top,
  1371.                     plfmDstRect.right - plfmDstRect.left,
  1372.                     plfmDstRect.bottom - plfmDstRect.top,
  1373.                     memoryDC,
  1374.                     plfmSrcRect.left, 
  1375.                     plfmSrcRect.top,
  1376.                     plfmSrcRect.right - plfmSrcRect.left,
  1377.                     plfmSrcRect.bottom - plfmSrcRect.top,
  1378.                     WinConvertRasterOp(ink->GetTransferMode()));
  1379.     
  1380.         if (hPalOld)
  1381.             ::SelectPalette(hDC, hPalOld, TRUE);
  1382.     
  1383.         ::SelectObject(memoryDC, oldBitmap);
  1384.         ::DeleteDC(memoryDC);
  1385. #endif
  1386. #ifdef FW_BUILD_MAC
  1387.         device->SelectInk(ink, FW_kImageShape, FW_kFill);    // Never use FW_kFrame for bitmap
  1388.         device->SetInGrafPort();
  1389.     
  1390.         PixMapHandle pmh = bitmap->MacLockPixels();
  1391.         ::CopyBits((BitMap*)*pmh, &FW_QDGlobals.thePort->portBits, 
  1392.                     &plfmSrcRect, &plfmDstRect, 
  1393.                     ink->GetTransferMode(), NULL);
  1394.         bitmap->MacUnlockPixels();
  1395. #endif
  1396.     }
  1397.     FW_SOM_CATCH
  1398. }
  1399.  
  1400. //----------------------------------------------------------------------------------------
  1401. //    FW_PrivRenderIcon
  1402. //----------------------------------------------------------------------------------------
  1403.  
  1404. void SL_API    FW_PrivRenderIcon(Environment* ev,
  1405.                             FW_SGraphicContext& gc,
  1406.                               FW_HIcon icon,
  1407.                             const FW_SRect& rect,
  1408.                             FW_RenderIconTransform transform,
  1409.                             FW_RenderIconAlignment alignment,
  1410.                             FW_ERenderVerbs renderVerb)
  1411. {
  1412.     FW_RENDER_PROLOG
  1413.     FW_CHECK_RENDER_VERB
  1414.  
  1415.     FW_ASSERT(icon != NULL);
  1416.     
  1417.     FW_SOM_TRY
  1418.     {
  1419.         FW_CPoint iconSize;
  1420.         icon->GetIconSize(iconSize);
  1421.         
  1422.         short xSize = iconSize.IntX(), ySize = iconSize.IntY();
  1423.     
  1424.         FW_SPlatformRect plfmDstRect;
  1425.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmDstRect);
  1426.         FW_FailOnEvError(ev);
  1427.         
  1428.         if(alignment != FW_kIconScaleToFit)
  1429.         {
  1430.             // Horizontal alignment
  1431.             switch((alignment & FW_kPrivIconHorzMask))
  1432.             {
  1433.             case FW_kIconAlignCenter:
  1434.                 plfmDstRect.left = (plfmDstRect.right + plfmDstRect.left - xSize) / 2;
  1435.                 // fall-through
  1436.     
  1437.             case FW_kIconAlignLeft:
  1438.                 plfmDstRect.right = plfmDstRect.left + xSize;
  1439.                 break;
  1440.     
  1441.             case FW_kIconAlignRight:
  1442.                 plfmDstRect.left = plfmDstRect.right - xSize;
  1443.                 break;
  1444.             }
  1445.             
  1446.             // Vertical alignment
  1447.             switch((alignment & FW_kPrivIconVertMask))
  1448.             {
  1449.             case FW_kIconAlignVCenter:
  1450.                 plfmDstRect.top = (plfmDstRect.top + plfmDstRect.bottom - ySize) / 2;
  1451.                 // fall-through
  1452.     
  1453.             case FW_kIconAlignTop:
  1454.                 plfmDstRect.bottom = plfmDstRect.top + ySize;
  1455.                 break;
  1456.     
  1457.             case FW_kIconAlignBottom:
  1458.                 plfmDstRect.top = plfmDstRect.bottom - ySize;
  1459.                 break;
  1460.             }
  1461.         }
  1462.         
  1463.         FW_PlatformIcon hIcon = icon->GetPlatformIcon();
  1464.     
  1465. #ifdef FW_BUILD_WIN
  1466.         // [HLX] Need to support tranform
  1467.         ::DrawIconEx(*device, plfmDstRect.left, plfmDstRect.top, hIcon,
  1468.             plfmDstRect.right - plfmDstRect.left,
  1469.             plfmDstRect.bottom - plfmDstRect.top,
  1470.             0, NULL, DI_NORMAL);
  1471. #endif
  1472. #ifdef FW_BUILD_MAC
  1473. #if defined(__MWERKS__) && GENERATING68K
  1474.         RGBColor macBlackColor;
  1475.         macBlackColor.red = macBlackColor.green = macBlackColor.blue = 0x0000;
  1476. #else
  1477.         RGBColor macBlackColor = { 0x0000, 0x0000, 0x0000 };
  1478. #endif
  1479.         ::RGBForeColor(&macBlackColor);
  1480. #if defined(__MWERKS__) && GENERATING68K
  1481.         RGBColor macWhiteColor;
  1482.         macWhiteColor.red = macWhiteColor.green = macWhiteColor.blue = 0xFFFF;
  1483. #else
  1484.         RGBColor macWhiteColor = { 0xFFFF, 0xFFFF, 0xFFFF };
  1485. #endif
  1486.         ::RGBBackColor(&macWhiteColor);
  1487.         ::PlotIconSuite(&plfmDstRect, atNone, transform, hIcon);
  1488. #endif
  1489.     }
  1490.     FW_SOM_CATCH
  1491. }
  1492.  
  1493. //========================================================================================
  1494. // Local helpers
  1495. //========================================================================================
  1496.  
  1497. //----------------------------------------------------------------------------------------
  1498. //    PrivTextBox
  1499. //----------------------------------------------------------------------------------------
  1500.  
  1501. static FW_PlatformCoordinate     PrivTextBox(Environment* ev,
  1502.                                     FW_CPrivGraphicsDevice* device,
  1503.                                     FW_CPrivTextBuffer *textBuffer, 
  1504.                                     const FW_CPlatformRect& box,
  1505.                                     FW_TextBoxOptions options,
  1506.                                     FW_Boolean draw,
  1507.                                     FW_HFont font)
  1508. {
  1509. FW_UNUSED(ev);
  1510.  
  1511.     if (textBuffer->IsDone())
  1512.         return box.top;
  1513.  
  1514.     // ----- Check options for consistency
  1515.     FW_TextBoxOptions opt = options;
  1516.  
  1517.     if (!draw)
  1518.         opt &= ~FW_kTextBoxClipToBox;
  1519.     
  1520.     if ((opt & FW_kTextBoxSingleLine) != 0)
  1521.     {
  1522.         opt &= ~FW_kTextBoxWordWrap;
  1523.         opt &= ~FW_kTextBoxWordBreak;
  1524.     }
  1525.     
  1526.     if ((opt & FW_kTextBoxWordWrap) != 0)
  1527.     {
  1528.         opt &= ~FW_kTextBoxJustifyBottom;
  1529.         opt &= ~FW_kTextBoxJustifyVCenter;
  1530.     }
  1531.  
  1532.     FW_CharacterPosition segStart;        // start of the current string segment
  1533.     FW_CharacterCount segLen;            // its length (charcter count)
  1534.     FW_PlatformCoordinate actualWidth;    // its actual width (pixels)
  1535.     FW_PlatformCoordinate maxWidth = box.right - box.left;
  1536.  
  1537.     FW_Boolean bClip = (opt & FW_kTextBoxClipToBox) != 0;
  1538.  
  1539. #ifdef FW_BUILD_WIN
  1540.     // ----- Set the clipping region if we need to
  1541.     HDC hDC = device->GetPlatformCanvas();
  1542.     int savedDC = 0;
  1543.     if (bClip)
  1544.     {
  1545.         savedDC = ::SaveDC(hDC);
  1546.         ::IntersectClipRect(hDC, 
  1547.                             box.left, box.top, 
  1548.                             box.right, box.bottom);
  1549.     }
  1550.  
  1551.     // ----- Get the font height
  1552.     TEXTMETRIC textMetric;
  1553.     ::GetTextMetrics(hDC, &textMetric);
  1554.     FW_PlatformCoordinate fontHeight = textMetric.tmHeight + textMetric.tmExternalLeading;
  1555.  
  1556.     FW_PlatformCoordinate drawPosY = box.top;
  1557.     FW_PlatformCoordinate drawPosX = box.left;
  1558. #endif
  1559. #ifdef FW_BUILD_MAC
  1560.     // ----- Set the clipping region if we need to
  1561.     RgnHandle oldClipRgn = 0;
  1562.     if (bClip)
  1563.     {
  1564.         oldClipRgn = device->GetClip();
  1565.         device->IntersectClipRect(box);
  1566.     }
  1567.  
  1568.     // ----- Get the font height -----
  1569.     FontInfo fi;
  1570.     ::GetFontInfo(&fi);
  1571.     FW_PlatformCoordinate fontHeight = fi.ascent + fi.descent + fi.leading;
  1572.  
  1573.     FW_PlatformCoordinate drawPosY = box.top + fi.ascent;
  1574.     FW_PlatformCoordinate drawPosX = box.left;
  1575.     
  1576.     FW_Boolean bIsStrikeOut = (font->GetFontStyle() & FW_kStrikeOut) != 0;
  1577. #endif
  1578.  
  1579.     // ----- Check vertical jusitficaiton
  1580.     switch (opt & FW_kPrivTextBoxVertJusificationMask)
  1581.     {
  1582.     case FW_kTextBoxJustifyVCenter:
  1583. #ifdef FW_BUILD_WIN
  1584.         drawPosY = (box.top + box.bottom - fontHeight) / 2;
  1585. #endif
  1586. #ifdef FW_BUILD_MAC
  1587.         drawPosY = (box.top + box.bottom + fi.ascent - fi.descent) / 2;
  1588. #endif
  1589.         break;
  1590.         
  1591.     case FW_kTextBoxJustifyBottom:
  1592.         drawPosY = box.bottom - fontHeight;
  1593.         break;
  1594.     }
  1595.  
  1596.     // ----- Draw string segments one by one
  1597.     FW_Boolean wordWrap = (opt & FW_kTextBoxWordWrap) != 0;
  1598.     FW_Boolean wordBreak = (opt & FW_kTextBoxWordBreak) != 0;
  1599.     FW_Boolean reachedBottom = FALSE;
  1600.     while (TRUE)
  1601.     {
  1602.         const char* line;
  1603.         FW_ByteCount lineLength;
  1604.         textBuffer->GetCurrentLine(line, lineLength);
  1605.         
  1606.         // ----- Draw the current segment
  1607.         FW_Boolean bCalledBefore = FALSE;
  1608.         while (!reachedBottom && FW_PrivGetStringSegment(*device, bCalledBefore,
  1609.             line, lineLength, segStart, segLen, maxWidth, actualWidth, wordWrap, wordBreak))
  1610.         {
  1611.             // ----- Check horizontal jusitficaiton
  1612.             switch (opt & FW_kPrivTextBoxHorzJusificationMask)
  1613.             {
  1614.             case FW_kTextAlignHCenter:
  1615.                 drawPosX = (box.left + box.right - actualWidth) / 2;
  1616.                 break;
  1617.             
  1618.             case FW_kTextAlignRight:
  1619.                 drawPosX = box.right - actualWidth;
  1620.                 break;
  1621.             }
  1622.  
  1623.             if (draw)
  1624.             {
  1625.                 // ----- Draw the next line -----
  1626. #ifdef FW_BUILD_WIN
  1627.                 ::TextOut(hDC, drawPosX, drawPosY, line + segStart, segLen);
  1628. #endif
  1629. #ifdef FW_BUILD_MAC
  1630.                 ::MoveTo(drawPosX, drawPosY);
  1631.                 ::DrawText((Ptr)line, segStart, segLen);
  1632.     
  1633.                 // ----- StrikeOut if necessary -----
  1634.                 if (bIsStrikeOut)
  1635.                     MacStrikeOut(device, drawPosX, drawPosY);
  1636. #endif
  1637.             }
  1638.             
  1639.             drawPosY += fontHeight;        // Move one line down
  1640.             line += segLen + segStart;    // move on to the next segment
  1641.             lineLength -= segLen + segStart;
  1642.             
  1643.             // see if we've gotten to the bottom of the rectangle and need not to continue
  1644.             reachedBottom = bClip && (drawPosY > box.bottom);
  1645.         }
  1646.         
  1647.         if (textBuffer->IsDone())
  1648.             break;
  1649.             
  1650.         if (reachedBottom)
  1651.             break;
  1652.     
  1653.         textBuffer->Advance();
  1654.     }
  1655.  
  1656.     // ----- Restore clipping region
  1657. #ifdef FW_BUILD_WIN
  1658.     if (savedDC != 0)
  1659.         ::RestoreDC(*device, savedDC);
  1660. #endif
  1661. #ifdef FW_BUILD_MAC
  1662.     if (oldClipRgn != NULL)
  1663.     {
  1664.         ::SetClip(oldClipRgn);
  1665.         ::DisposeRgn(oldClipRgn);
  1666.     }
  1667.     
  1668. #endif
  1669.  
  1670.     // ----- Return the result ----
  1671. #ifdef FW_BUILD_WIN
  1672.     return drawPosY;
  1673. #endif
  1674. #ifdef FW_BUILD_MAC
  1675.     return drawPosY - fi.ascent;
  1676. #endif
  1677. }
  1678.  
  1679. #ifdef FW_BUILD_MAC
  1680.  
  1681. //========================================================================================
  1682. // Macintosh-specific implementation
  1683. //========================================================================================
  1684.  
  1685. //----------------------------------------------------------------------------------------
  1686. //    MacSelectInkAndStyle
  1687. //----------------------------------------------------------------------------------------
  1688.  
  1689. static FW_Boolean MacSelectInkAndStyle(
  1690.                         FW_CPrivGraphicsDevice* device,
  1691.                         FW_EPrivShapeCategories shapeCategory,
  1692.                         FW_ERenderVerbs renderVerb,
  1693.                         FW_HInk ink,
  1694.                         FW_HStyle style)
  1695. {
  1696.     
  1697.     device->SelectInk(ink, shapeCategory, renderVerb);
  1698.     FW_Boolean styleIsDash = device->SelectStyle(style, ink->GetTransferMode());
  1699.     device->SetInGrafPort();
  1700.     return styleIsDash;
  1701. }
  1702.  
  1703. //----------------------------------------------------------------------------------------
  1704. //    MacCalcTextPosition
  1705. //----------------------------------------------------------------------------------------
  1706.  
  1707. static FW_CPlatformPoint MacCalcTextPosition(
  1708.                             FW_CPrivGraphicsDevice* device,
  1709.                             short byteCount, const char* text,
  1710.                             FW_TextAlignment textAlignment,
  1711.                             const FW_CPlatformPoint& position)
  1712. {
  1713.     FW_ASSERT(device->GetPlatformCanvas() == FW_QDGlobals.thePort);
  1714.  
  1715.     FW_ASSERT(text != NULL);
  1716.  
  1717.     FW_CPlatformPoint plfmPos(position);
  1718.  
  1719.     if((textAlignment & FW_kPrivTextAlignUsePosMask) == FW_kTextAlignUseCurrentPos)
  1720.     {
  1721.         ::GetPen(&plfmPos);
  1722.     }
  1723.     else
  1724.     {
  1725.         // ----- Adjust Horizontal position
  1726.         FW_TextAlignment hAlign = textAlignment & FW_kPrivTextAlignHorzAlignMask;
  1727.         if (hAlign != FW_kTextAlignLeft)
  1728.         {
  1729.             short textWidth = ::TextWidth(text, 0, byteCount);
  1730.             if (hAlign == FW_kTextAlignRight)
  1731.                 plfmPos.h -= textWidth;
  1732.             else
  1733.                 plfmPos.h -= (textWidth / 2);
  1734.         }
  1735.     }
  1736.     
  1737.     // ----- In both cases we need to adjust the vertical position
  1738.     FW_TextAlignment vAlign = textAlignment & FW_kPrivTextAlignVertAlignMask;
  1739.     if (vAlign != FW_kTextAlignBaseLine)
  1740.     {
  1741.         FontInfo fi;
  1742.         ::GetFontInfo(&fi);
  1743.         switch (vAlign)
  1744.         {
  1745.             case FW_kTextAlignTop:
  1746.                 plfmPos.v += fi.ascent;
  1747.                 break;
  1748.                 
  1749.             case FW_kTextAlignBottom:
  1750.                 plfmPos.v -= fi.descent;
  1751.                 break;
  1752.                 
  1753.             case FW_kTextAlignVCenter:
  1754.                 plfmPos.v += fi.ascent - ((fi.descent + fi.ascent) / 2);
  1755.                 break;
  1756.         }
  1757.     }
  1758.  
  1759.     return plfmPos;
  1760. }
  1761.  
  1762. //----------------------------------------------------------------------------------------
  1763. //    MacStrikeOut
  1764. //----------------------------------------------------------------------------------------
  1765.  
  1766. static void MacStrikeOut(
  1767.         FW_CPrivGraphicsDevice* device,
  1768.         short beforePosX, short beforePosY)
  1769. {
  1770.     // ----- Get the pen position before drawing -----
  1771.     FW_CPlatformPoint afterPoint;
  1772.     ::GetPen(&afterPoint);
  1773.  
  1774.     FontInfo fi;
  1775.     ::GetFontInfo(&fi);
  1776.     short ySize = (fi.ascent + fi.descent) / 2;
  1777.  
  1778.     device->SetPenSize(1,1);
  1779.     device->SetInGrafPort();
  1780.     
  1781.     ::MoveTo(beforePosX, beforePosY - ySize);
  1782.     ::LineTo(afterPoint.h - 1, afterPoint.v - ySize);
  1783.     
  1784.     // ----- Restore the pen position -----
  1785.     ::MoveTo(afterPoint.h, afterPoint.v);
  1786. }
  1787.  
  1788. #endif
  1789.  
  1790. #ifdef FW_BUILD_WIN
  1791.  
  1792. //========================================================================================
  1793. // Windows-specific implementation
  1794. //========================================================================================
  1795.  
  1796. static const DWORD FW_gWinRasterOps[11] =    
  1797. {
  1798.     SRCCOPY,        //    FW_kCopy
  1799.     NOTSRCCOPY,        //     FW_kNotCopy
  1800.     SRCPAINT,        //  FW_kOr
  1801.     MERGEPAINT,        //    FW_kNotOr
  1802.     SRCINVERT,        //    FW_kXOr
  1803.     0x00990066UL,    //    FW_kNotXOr
  1804.     SRCAND,            //    FW_kClear
  1805.     0x00440328UL,    //    FW_kNotClear
  1806.     SRCINVERT,         //    FW_kHilite
  1807.     SRCCOPY,         //    FW_kErase
  1808.     SRCINVERT         //    FW_kInvert
  1809. };
  1810.  
  1811. //----------------------------------------------------------------------------------------
  1812. //    WinConvertRasterOp
  1813. //----------------------------------------------------------------------------------------
  1814.  
  1815. DWORD WinConvertRasterOp(FW_TransferModes transferMode)
  1816. {
  1817.     if ((transferMode & 0xFFFF0000L) == 0)
  1818.         return (DWORD)transferMode;        // Native Raster ops
  1819.     else
  1820.     {
  1821.         FW_ASSERT(transferMode <= FW_kLastTransferMode);
  1822.         return FW_gWinRasterOps[transferMode & 0x0000FFFFL];
  1823.     }
  1824. }
  1825.  
  1826. #endif
  1827.